Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModelTest.kt baef2a594d02337a0914df2f9e3782ec07d68195 (baef2a59) Text, 61.63 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.settings.radio

Tff7b72import T7ee787androidx.lifecycle.viewModelScope
Tff7b72import T7ee787app.cash.turbine.test
Tff7b72import T7ee787dev.mokkery.MockMode
Tff7b72import T7ee787dev.mokkery.answering.calls
Tff7b72import T7ee787dev.mokkery.answering.returns
Tff7b72import T7ee787dev.mokkery.every
Tff7b72import T7ee787dev.mokkery.everySuspend
Tff7b72import T7ee787dev.mokkery.matcher.any
Tff7b72import T7ee787dev.mokkery.mock
Tff7b72import T7ee787dev.mokkery.verify
Tff7b72import T7ee787dev.mokkery.verify.VerifyMode.Companion.exactly
Tff7b72import T7ee787dev.mokkery.verifySuspend
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.Dispatchers
Tff7b72import T7ee787kotlinx.coroutines.ExperimentalCoroutinesApi
Tff7b72import T7ee787kotlinx.coroutines.SupervisorJob
Tff7b72import T7ee787kotlinx.coroutines.cancel
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableSharedFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.test.UnconfinedTestDispatcher
Tff7b72import T7ee787kotlinx.coroutines.test.advanceTimeBy
Tff7b72import T7ee787kotlinx.coroutines.test.advanceUntilIdle
Tff7b72import T7ee787kotlinx.coroutines.test.resetMain
Tff7b72import T7ee787kotlinx.coroutines.test.runCurrent
Tff7b72import T7ee787kotlinx.coroutines.test.runTest
Tff7b72import T7ee787kotlinx.coroutines.test.setMain
Tff7b72import T7ee787okio.ByteString.Companion.encodeUtf8
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.AdminActionsUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.ExportProfileUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.ImportProfileUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.ImportSecurityConfigUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.InstallProfileUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.ProcessRadioResponseUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.RadioConfigUseCase
Tff7b72import T7ee787org.meshtastic.core.domain.usecase.settings.RadioResponseResult
Tff7b72import T7ee787org.meshtastic.core.model.ConnectionState
Tff7b72import T7ee787org.meshtastic.core.model.MqttProbeStatus
Tff7b72import T7ee787org.meshtastic.core.model.MyNodeInfo
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.repository.AnalyticsPrefs
Tff7b72import T7ee787org.meshtastic.core.repository.FileService
Tff7b72import T7ee787org.meshtastic.core.repository.HomoglyphPrefs
Tff7b72import T7ee787org.meshtastic.core.repository.LocationRepository
Tff7b72import T7ee787org.meshtastic.core.repository.LocationService
Tff7b72import T7ee787org.meshtastic.core.repository.MapConsentPrefs
Tff7b72import T7ee787org.meshtastic.core.repository.MqttManager
Tff7b72import T7ee787org.meshtastic.core.repository.NodeRestartTracker
Tff7b72import T7ee787org.meshtastic.core.repository.PacketRepository
Tff7b72import T7ee787org.meshtastic.core.repository.RadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.repository.SecurityKeyBackupStore
Tff7b72import T7ee787org.meshtastic.core.repository.ServiceRepository
Tff7b72import T7ee787org.meshtastic.core.repository.StoredSecurityKeys
Tff7b72import T7ee787org.meshtastic.core.repository.UiPrefs
Tff7b72import T7ee787org.meshtastic.core.testing.FakeLockdownCoordinator
Tff7b72import T7ee787org.meshtastic.core.testing.FakeNodeRepository
Tff7b72import T7ee787org.meshtastic.core.ui.util.SnackbarManager
Tff7b72import T7ee787org.meshtastic.feature.settings.navigation.ConfigRoute
Tff7b72import T7ee787org.meshtastic.proto.Channel
Tff7b72import T7ee787org.meshtastic.proto.ChannelSet
Tff7b72import T7ee787org.meshtastic.proto.ChannelSettings
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.proto.Data
Tff7b72import T7ee787org.meshtastic.proto.DeviceMetadata
Tff7b72import T7ee787org.meshtastic.proto.DeviceProfile
Tff7b72import T7ee787org.meshtastic.proto.HamParameters
Tff7b72import T7ee787org.meshtastic.proto.LoRaPresetGroup
Tff7b72import T7ee787org.meshtastic.proto.LoRaRegionPresetMap
Tff7b72import T7ee787org.meshtastic.proto.LocalConfig
Tff7b72import T7ee787org.meshtastic.proto.LocalModuleConfig
Tff7b72import T7ee787org.meshtastic.proto.MeshPacket
Tff7b72import T7ee787org.meshtastic.proto.User
Tff7b72import T7ee787kotlin.test.AfterTest
Tff7b72import T7ee787kotlin.test.BeforeTest
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertFailsWith
Tff7b72import T7ee787kotlin.test.assertFalse
Tff7b72import T7ee787kotlin.test.assertNotNull
Tff7b72import T7ee787kotlin.test.assertTrue
Tff7b72import T7ee787kotlin.time.Duration

Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalCoroutinesApiTff7b72::Te6edf3classTb4b4b4)
Tff7b72class T56d364RadioConfigViewModelTest Tb4b4b4{

Tff7b72private Tff7b72val Te6edf3testDispatcher Tff7b72= Te6edf3UnconfinedTestDispatcherTb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3radioConfigRepositoryTb4b4b4: Te6edf3RadioConfigRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3packetRepositoryTb4b4b4: Te6edf3PacketRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3serviceRepositoryTb4b4b4: Te6edf3ServiceRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3nodeRepository Tff7b72= Te6edf3FakeNodeRepositoryTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3locationRepositoryTb4b4b4: Te6edf3LocationRepository Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3mapConsentPrefsTb4b4b4: Te6edf3MapConsentPrefs Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3analyticsPrefsTb4b4b4: Te6edf3AnalyticsPrefs Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3homoglyphEncodingPrefsTb4b4b4: Te6edf3HomoglyphPrefs Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)

Tff7b72private Tff7b72val Te6edf3importProfileUseCaseTb4b4b4: Te6edf3ImportProfileUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3exportProfileUseCaseTb4b4b4: Te6edf3ExportProfileUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3importSecurityConfigUseCaseTb4b4b4: Te6edf3ImportSecurityConfigUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3installProfileUseCaseTb4b4b4: Te6edf3InstallProfileUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3radioConfigUseCaseTb4b4b4: Te6edf3RadioConfigUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3adminActionsUseCaseTb4b4b4: Te6edf3AdminActionsUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3processRadioResponseUseCaseTb4b4b4: Te6edf3ProcessRadioResponseUseCase Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3locationServiceTb4b4b4: Te6edf3LocationService Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3fileServiceTb4b4b4: Te6edf3FileService Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3mqttManagerTb4b4b4: Te6edf3MqttManager Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3uiPrefsTb4b4b4: Te6edf3UiPrefs Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3securityKeyBackupStoreTb4b4b4: Te6edf3SecurityKeyBackupStore Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3snackbarManagerTb4b4b4: Te6edf3SnackbarManager Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)
Tff7b72private Tff7b72val Te6edf3trackerScope Tff7b72= Te6edf3CoroutineScopeTb4b4b4(Te6edf3SupervisorJobTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3nodeRestartTracker Tff7b72= Te6edf3NodeRestartTrackerTb4b4b4(Te6edf3trackerScopeTb4b4b4)

T8b949e/**
* A `viewModelScope` is not a child of `runTest`, so work still in flight when a test ends would resume on
* `Dispatchers.Main` after [Dispatchers.resetMain] and fail an unrelated later test. Every ViewModel is tracked
* here so [tearDown] can cancel it.
*/
Tff7b72private Tff7b72val Te6edf3createdViewModels Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3RadioConfigViewModelTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72lateinit Tff7b72var Te6edf3viewModelTb4b4b4: Te6edf3RadioConfigViewModel

Tf0883e@BeforeTest
Tff7b72fun Td2a8ffsetUpTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3DispatchersTb4b4b4.Te6edf3setMainTb4b4b4(Te6edf3testDispatcherTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3deviceProfileFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3DeviceProfileTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3localConfigFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3LocalConfigTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3channelSetFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3ChannelSetTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3moduleConfigFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3LocalModuleConfigTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3deviceUIConfigFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72nullTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3fileManifestFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3loraRegionPresetMapFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72nullTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3analyticsPrefsTb4b4b4.Te6edf3analyticsAllowed Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3homoglyphEncodingPrefsTb4b4b4.Te6edf3homoglyphEncodingEnabled Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3MutableSharedFlowTb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3connectionState Tb4b4b4} Te6edf3returns
Te6edf3MutableStateFlowTb4b4b4(Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3coreTb4b4b4.Te6edf3modelTb4b4b4.Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3mqttConnectionState Tb4b4b4} Te6edf3returns
Te6edf3MutableStateFlowTb4b4b4(Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3coreTb4b4b4.Te6edf3modelTb4b4b4.Te6edf3MqttConnectionStateTb4b4b4.Te6edf3InactiveTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3proxyActive Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3uiPrefsTb4b4b4.Te6edf3showQuickChat Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72falseTb4b4b4)

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tf0883e@AfterTest
Tff7b72fun Td2a8fftearDownTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3createdViewModelsTb4b4b4.Te6edf3forEach Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3viewModelScopeTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3createdViewModelsTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Te6edf3trackerScopeTb4b4b4.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3DispatchersTb4b4b4.Te6edf3resetMainTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffcreateViewModelTb4b4b4(Te6edf3destNumTb4b4b4: Tffa657Int? Tff7b72= Tff7b72nullTb4b4b4) Tff7b72= Te6edf3RadioConfigViewModelTb4b4b4(
Te6edf3destNum Tff7b72= Te6edf3destNumTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Te6edf3packetRepository Tff7b72= Te6edf3packetRepositoryTb4b4b4,
Te6edf3serviceRepository Tff7b72= Te6edf3serviceRepositoryTb4b4b4,
Te6edf3nodeRepository Tff7b72= Te6edf3nodeRepositoryTb4b4b4,
Te6edf3locationRepository Tff7b72= Te6edf3locationRepositoryTb4b4b4,
Te6edf3mapConsentPrefs Tff7b72= Te6edf3mapConsentPrefsTb4b4b4,
Te6edf3analyticsPrefs Tff7b72= Te6edf3analyticsPrefsTb4b4b4,
Te6edf3homoglyphEncodingPrefs Tff7b72= Te6edf3homoglyphEncodingPrefsTb4b4b4,
Te6edf3importProfileUseCase Tff7b72= Te6edf3importProfileUseCaseTb4b4b4,
Te6edf3exportProfileUseCase Tff7b72= Te6edf3exportProfileUseCaseTb4b4b4,
Te6edf3importSecurityConfigUseCase Tff7b72= Te6edf3importSecurityConfigUseCaseTb4b4b4,
Te6edf3securityKeyBackupStore Tff7b72= Te6edf3securityKeyBackupStoreTb4b4b4,
Te6edf3snackbarManager Tff7b72= Te6edf3snackbarManagerTb4b4b4,
Te6edf3nodeRestartTracker Tff7b72= Te6edf3nodeRestartTrackerTb4b4b4,
Te6edf3installProfileUseCase Tff7b72= Te6edf3installProfileUseCaseTb4b4b4,
Te6edf3radioConfigUseCase Tff7b72= Te6edf3radioConfigUseCaseTb4b4b4,
Te6edf3adminActionsUseCase Tff7b72= Te6edf3adminActionsUseCaseTb4b4b4,
Te6edf3processRadioResponseUseCase Tff7b72= Te6edf3processRadioResponseUseCaseTb4b4b4,
Te6edf3locationService Tff7b72= Te6edf3locationServiceTb4b4b4,
Te6edf3fileService Tff7b72= Te6edf3fileServiceTb4b4b4,
Te6edf3mqttManager Tff7b72= Te6edf3mqttManagerTb4b4b4,
Te6edf3lockdownCoordinator Tff7b72= Te6edf3FakeLockdownCoordinatorTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3analytics Tff7b72= Te6edf3mockTb4b4b4(Te6edf3MockModeTb4b4b4.Te6edf3autofillTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4.Te6edf3also Tb4b4b4{ Te6edf3createdViewModels Tff7b72+Tff7b72= Tffa657it Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setConfig calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3config Tff7b72= Te6edf3ConfigTb4b4b4(Te6edf3device Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4(Te6edf3role Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3ROUTERTb4b4b4)Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3configTb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3test Tb4b4b4{
Tff7b72val Te6edf3state Tff7b72= Te6edf3awaitItemTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3ROUTERTb4b4b4, Te6edf3stateTb4b4b4.Te6edf3radioConfigTb4b4b4.Te6edf3deviceTff7b72?.Te6edf3roleTb4b4b4)
Te6edf3cancelAndIgnoreRemainingEventsTb4b4b4(Tb4b4b4)
Tb4b4b4}

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3configTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`toggleAnalyticsAllowed calls prefs`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3every Tb4b4b4{ Te6edf3analyticsPrefsTb4b4b4.Te6edf3analyticsAllowed Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72trueTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3analyticsPrefsTb4b4b4.Te6edf3setAnalyticsAllowedTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3toggleAnalyticsAllowedTb4b4b4(Tb4b4b4)

Te6edf3verify Tb4b4b4{ Te6edf3analyticsPrefsTb4b4b4.Te6edf3setAnalyticsAllowedTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`toggleHomoglyphCharactersEncodingEnabled calls prefs`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3every Tb4b4b4{ Te6edf3homoglyphEncodingPrefsTb4b4b4.Te6edf3homoglyphEncodingEnabled Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Tff7b72trueTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3homoglyphEncodingPrefsTb4b4b4.Te6edf3setHomoglyphEncodingEnabledTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3toggleHomoglyphCharactersEncodingEnabledTb4b4b4(Tb4b4b4)

Te6edf3verify Tb4b4b4{ Te6edf3homoglyphEncodingPrefsTb4b4b4.Te6edf3setHomoglyphEncodingEnabledTb4b4b4(Tff7b72falseTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`processPacketResponse updates state on metadata result`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3packet Tff7b72= Te6edf3MeshPacketTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3metadata Tff7b72= Te6edf3DeviceMetadataTb4b4b4(Te6edf3firmware_version Tff7b72= Ta5d6ff"Ta5d6ff3.0.0Ta5d6ff"Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3MetadataTb4b4b4(Te6edf3metadataTb4b4b4)

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3packetTb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3test Tb4b4b4{
Tff7b72val Te6edf3state Tff7b72= Te6edf3awaitItemTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ff3.0.0Ta5d6ff"Tb4b4b4, Te6edf3stateTb4b4b4.Te6edf3metadataTff7b72?.Te6edf3firmware_versionTb4b4b4)
Te6edf3cancelAndIgnoreRemainingEventsTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`probeMqttConnection updates status for success`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3everySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Ta5d6ff"Ta5d6ffuserTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpassTa5d6ff"Tb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3calls Tb4b4b4{
Te6edf3delayTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3MqttProbeStatusTb4b4b4.Te6edf3SuccessTb4b4b4(Te6edf3serverInfo Tff7b72= Ta5d6ff"Ta5d6ffclient=testTa5d6ff"Tb4b4b4)
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3probeMqttConnectionTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Ta5d6ff"Ta5d6ffuserTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpassTa5d6ff"Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3MqttProbeStatusTb4b4b4.Te6edf3ProbingTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)

Te6edf3advanceTimeByTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3MqttProbeStatusTb4b4b4.Te6edf3SuccessTb4b4b4(Te6edf3serverInfo Tff7b72= Ta5d6ff"Ta5d6ffclient=testTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Ta5d6ff"Ta5d6ffuserTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpassTa5d6ff"Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`probeMqttConnection updates status for timeout`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3everySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72falseTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3MqttProbeStatusTb4b4b4.Te6edf3TimeoutTb4b4b4(T79c0ff5Te6edf3_000Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3probeMqttConnectionTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72falseTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3MqttProbeStatusTb4b4b4.Te6edf3TimeoutTb4b4b4(T79c0ff5Te6edf3_000Tb4b4b4)Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72falseTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`probeMqttConnection converts thrown exception to other status`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3everySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3calls Tb4b4b4{ Tff7b72throw Te6edf3IllegalStateExceptionTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4) Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3probeMqttConnectionTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3MqttProbeStatusTb4b4b4.Te6edf3OtherTb4b4b4(Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72trueTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setMqttProxyActive false stops the proxy without touching device config`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3every Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3stopTb4b4b4(Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3setMqttProxyActiveTb4b4b4(Tff7b72falseTb4b4b4)

Te6edf3verify Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3stopTb4b4b4(Tb4b4b4) Tb4b4b4}
T8b949e// Phone-local cut must not issue any device config read/write.
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setModuleConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setMqttProxyActive true restarts proxy using current device module config`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3moduleConfigFlow Tb4b4b4} Te6edf3returns
Te6edf3MutableStateFlowTb4b4b4(
Te6edf3LocalModuleConfigTb4b4b4(
Te6edf3mqtt Tff7b72= Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleConfigTb4b4b4.Te6edf3MQTTConfigTb4b4b4(Te6edf3enabled Tff7b72= Tff7b72trueTb4b4b4, Te6edf3proxy_to_client_enabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3startProxyTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3setMqttProxyActiveTb4b4b4(Tff7b72trueTb4b4b4)

Te6edf3verify Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3startProxyTb4b4b4(Tff7b72trueTb4b4b4, Tff7b72trueTb4b4b4) Tb4b4b4}
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setModuleConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setMqttProxyActive true is a no-op start when device MQTT is disabled`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3moduleConfigFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3LocalModuleConfigTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3startProxyTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3setMqttProxyActiveTb4b4b4(Tff7b72trueTb4b4b4)

T8b949e// The manager is still asked to start, but with both flags false it does nothing (its own guard).
Te6edf3verify Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3startProxyTb4b4b4(Tff7b72falseTb4b4b4, Tff7b72falseTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`clearMqttProbeStatus resets probe state`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3everySuspend Tb4b4b4{ Te6edf3mqttManagerTb4b4b4.Te6edf3probeTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72falseTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3calls Tb4b4b4{
Te6edf3delayTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3MqttProbeStatusTb4b4b4.Te6edf3SuccessTb4b4b4(Te6edf3serverInfo Tff7b72= Ta5d6ff"Ta5d6ffclient=testTa5d6ff"Tb4b4b4)
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3probeMqttConnectionTb4b4b4(Ta5d6ff"Ta5d6ffmqtt.example.comTa5d6ff"Tb4b4b4, Tff7b72falseTb4b4b4, Tff7b72nullTb4b4b4, Tff7b72nullTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3MqttProbeStatusTb4b4b4.Te6edf3ProbingTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3clearMqttProbeStatusTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tff7b72nullTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)

Te6edf3advanceTimeByTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Tff7b72nullTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3mqttProbeStatusTb4b4b4.Te6edf3valueTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels calls useCase for each changed channel`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3old Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffNewTa5d6ff"Tb4b4b4)Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3channelListTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels writes changed channels sequentially in index order`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3channelA Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3channelB Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3channelC Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelBTb4b4b4, Te6edf3channelCTb4b4b4)
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelCTb4b4b4, Te6edf3channelBTb4b4b4)
Tff7b72val Te6edf3writtenIndexes Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657IntTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3activeWrites Tff7b72= T79c0ff0
Tff7b72var Te6edf3maxConcurrentWrites Tff7b72= T79c0ff0

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tff7b72val Te6edf3channel Tff7b72= Tffa657itTb4b4b4.Te6edf3argsTff7b72[T79c0ff1Tff7b72] Tff7b72as Te6edf3Channel
Te6edf3activeWritesTff7b72+Tff7b72+
Te6edf3maxConcurrentWrites Tff7b72= Te6edf3maxOfTb4b4b4(Te6edf3maxConcurrentWritesTb4b4b4, Te6edf3activeWritesTb4b4b4)
Te6edf3writtenIndexesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3channelTb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3delayTb4b4b4(T79c0ff1Tb4b4b4)
Te6edf3activeWritesTff7b72-Tff7b72-
Te6edf3writtenIndexesTb4b4b4.Te6edf3size
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4, Te6edf3writtenIndexesTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3maxConcurrentWritesTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3channelListTb4b4b4)
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels waits for all ordered writes before success`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3Success
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3channelA Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3channelB Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3channelC Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelBTb4b4b4, Te6edf3channelCTb4b4b4)
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelCTb4b4b4, Te6edf3channelBTb4b4b4)
Tff7b72var Te6edf3nextPacketId Tff7b72= T79c0ff4T79c0ff0

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tff7b72val Te6edf3id Tff7b72= Tff7b72+Tff7b72+Te6edf3nextPacketId
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(Te6edf3idTb4b4b4)
Te6edf3id
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Te6edf3decoded Tff7b72= Te6edf3DataTb4b4b4(Te6edf3request_id Tff7b72= T79c0ff4T79c0ff1Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3midBatchState Tff7b72= Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState
Te6edf3assertTrueTb4b4b4(Te6edf3midBatchState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3midBatchStateTb4b4b4.Te6edf3totalTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3midBatchStateTb4b4b4.Te6edf3completedTb4b4b4)

Te6edf3advanceTimeByTb4b4b4(Te6edf3MANUAL_CHANNEL_WRITE_DELAYTb4b4b4.Te6edf3inWholeMillisecondsTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Te6edf3decoded Tff7b72= Te6edf3DataTb4b4b4(Te6edf3request_id Tff7b72= T79c0ff4T79c0ff2Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3SuccessTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels reconciles applied channel writes when ordered write fails`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3fourChannelFixtureTb4b4b4(Tb4b4b4)
Tff7b72val Tb4b4b4(Te6edf3channelATb4b4b4, Te6edf3_Tb4b4b4, Te6edf3_Tb4b4b4, Te6edf3channelDTb4b4b4) Tff7b72= Te6edf3old
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelDTb4b4b4)
Tff7b72val Te6edf3partiallyApplied Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelDTb4b4b4, Te6edf3oldTff7b72[T79c0ff2Tff7b72]Tb4b4b4, Te6edf3oldTff7b72[T79c0ff3Tff7b72]Tb4b4b4)
Tff7b72val Te6edf3writtenIndexes Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657IntTff7b72>Tb4b4b4(Tb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3channelSetFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tff7b72val Te6edf3channel Tff7b72= Tffa657itTb4b4b4.Te6edf3argsTff7b72[T79c0ff1Tff7b72] Tff7b72as Te6edf3Channel
Te6edf3writtenIndexesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3channelTb4b4b4.Te6edf3indexTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3writtenIndexesTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3IllegalStateExceptionTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)
Tb4b4b4}
Te6edf3channelTb4b4b4.Te6edf3index Tff7b72+ T79c0ff1T79c0ff0T79c0ff0
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4, Te6edf3writtenIndexesTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3partiallyAppliedTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3channelListTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3ErrorTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3packetRepositoryTb4b4b4.Te6edf3migrateChannelsByPSKTb4b4b4(Te6edf3oldTb4b4b4, Te6edf3partiallyAppliedTb4b4b4) Tb4b4b4}
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3replaceAllSettingsTb4b4b4(Te6edf3partiallyAppliedTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels serializes overlapping channel saves`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3fourChannelFixtureTb4b4b4(Tb4b4b4)
Tff7b72val Tb4b4b4(Te6edf3channelATb4b4b4, Te6edf3_Tb4b4b4, Te6edf3channelCTb4b4b4, Te6edf3channelDTb4b4b4) Tff7b72= Te6edf3old
Tff7b72val Te6edf3firstNew Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelDTb4b4b4)
Tff7b72val Te6edf3secondNew Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelCTb4b4b4)
Tff7b72val Te6edf3writtenChannels Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657StringTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3firstWrite Tff7b72= Tff7b72true

Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3channelSetFlow Tb4b4b4} Te6edf3returns Te6edf3MutableStateFlowTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tff7b72val Te6edf3channel Tff7b72= Tffa657itTb4b4b4.Te6edf3argsTff7b72[T79c0ff1Tff7b72] Tff7b72as Te6edf3Channel
Te6edf3writtenChannelsTb4b4b4.Te6edf3addTb4b4b4(Ta5d6ff"Tffd700${Te6edf3channelTb4b4b4.Te6edf3indexTffd700}Ta5d6ff:Tffd700${Te6edf3channelTb4b4b4.Te6edf3roleTffd700}Ta5d6ff:Tffd700${Te6edf3channelTb4b4b4.Te6edf3settingsTff7b72?.Te6edf3nameTb4b4b4.Te6edf3orEmptyTb4b4b4(Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3firstWriteTb4b4b4) Tb4b4b4{
Te6edf3firstWrite Tff7b72= Tff7b72false
Te6edf3delayTb4b4b4(T79c0ff1T79c0ff0Te6edf3_000Tb4b4b4)
Tb4b4b4}
Te6edf3writtenChannelsTb4b4b4.Te6edf3size
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3firstNewTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3secondNewTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Ta5d6ff"Ta5d6ff1:SECONDARY:DTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff2:DISABLED:Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff3:DISABLED:Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff1:SECONDARY:CTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3writtenChannelsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3secondNewTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3channelListTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`updateChannels does not start manual batch while another radio request is pending`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3old Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffNewTa5d6ff"Tb4b4b4)Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
Te6edf3delayTb4b4b4(T79c0ff1T79c0ff0Te6edf3_000Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff1T79c0ff0T79c0ff0

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3routeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}

Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`aborted manual batch preserves unrelated pending request`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3fourChannelFixtureTb4b4b4(Tb4b4b4)
Tff7b72val Tb4b4b4(Te6edf3channelATb4b4b4, Te6edf3_Tb4b4b4, Te6edf3_Tb4b4b4, Te6edf3channelDTb4b4b4) Tff7b72= Te6edf3old
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelDTb4b4b4)
Tff7b72val Te6edf3owner Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4, Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffUpdatedTa5d6ff"Tb4b4b4)
Tff7b72var Te6edf3writeCount Tff7b72= T79c0ff0

Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Te6edf3writeCountTff7b72+Tff7b72+
Tff7b72if Tb4b4b4(Te6edf3writeCount Tff7b72=Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Tff7b72throw Te6edf3IllegalStateExceptionTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)
T79c0ff1T79c0ff0T79c0ff0
Tb4b4b4}
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tff7b72val Te6edf3pendingRequestIds Tff7b72= Tffa657itTb4b4b4.Te6edf3argsTff7b72[T79c0ff2Tff7b72] Tff7b72as Te6edf3SetTff7b72<Tffa657IntTff7b72>
Tff7b72if Tb4b4b4(T79c0ff4T79c0ff2 Tff7b72in Te6edf3pendingRequestIdsTb4b4b4) Te6edf3RadioResponseResultTb4b4b4.Te6edf3OwnerTb4b4b4(Te6edf3ownerTb4b4b4) Tff7b72else Tff7b72null
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3advanceTimeByTb4b4b4(Te6edf3MANUAL_CHANNEL_WRITE_DELAYTb4b4b4.Te6edf3inWholeMillisecondsTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Te6edf3decoded Tff7b72= Te6edf3DataTb4b4b4(Te6edf3request_id Tff7b72= T79c0ff4T79c0ff2Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3ownerTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3userConfigTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`aborted manual batch cancels batch timeout before packet id reuse`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3old Tff7b72= Te6edf3fourChannelFixtureTb4b4b4(Tb4b4b4)
Tff7b72val Tb4b4b4(Te6edf3channelATb4b4b4, Te6edf3_Tb4b4b4, Te6edf3_Tb4b4b4, Te6edf3channelDTb4b4b4) Tff7b72= Te6edf3old
Tff7b72val Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelDTb4b4b4)
Tff7b72var Te6edf3writeCount Tff7b72= T79c0ff0

Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Te6edf3writeCountTff7b72+Tff7b72+
Tff7b72if Tb4b4b4(Te6edf3writeCount Tff7b72=Tff7b72= T79c0ff2Tb4b4b4) Tff7b72throw Te6edf3IllegalStateExceptionTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)
T79c0ff1T79c0ff0T79c0ff0
Tb4b4b4}
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)
T79c0ff1T79c0ff0T79c0ff0
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3newTb4b4b4, Te6edf3oldTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3advanceTimeByTb4b4b4(Te6edf3MANUAL_CHANNEL_WRITE_DELAYTb4b4b4.Te6edf3inWholeMillisecondsTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3advanceTimeByTb4b4b4(T79c0ff2T79c0ff9Te6edf3_500Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`applyManualChannelUpdatePlan paces writes except after final channel`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3channelA Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff1Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3channelB Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff2Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3channelC Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff3Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3writtenIndexes Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657IntTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3registeredRequestIds Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657IntTff7b72>Tb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3delays Tff7b72= Te6edf3mutableListOfTff7b72<Te6edf3DurationTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3result Tff7b72=
Te6edf3applyManualChannelUpdatePlanTb4b4b4(
Te6edf3updatePlan Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelBTb4b4b4, Te6edf3channelCTb4b4b4)Tb4b4b4,
Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffoldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3finalSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffnewTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3writeChannel Tff7b72= Tb4b4b4{ Te6edf3channelTb4b4b4, Te6edf3onRequestId Tff7b72-Tff7b72>
Te6edf3writtenIndexesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3channelTb4b4b4.Te6edf3indexTb4b4b4)
Tff7b72val Te6edf3id Tff7b72= Te6edf3channelTb4b4b4.Te6edf3index Tff7b72+ T79c0ff1T79c0ff0T79c0ff0
Te6edf3onRequestIdTb4b4b4(Te6edf3idTb4b4b4)
Te6edf3id
Tb4b4b4}Tb4b4b4,
Te6edf3registerRequestId Tff7b72= Tb4b4b4{ Te6edf3registeredRequestIdsTb4b4b4.Te6edf3addTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3delayFn Tff7b72= Tb4b4b4{ Te6edf3delaysTb4b4b4.Te6edf3addTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4)Tb4b4b4, Te6edf3writtenIndexesTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1T79c0ff0T79c0ff1Tb4b4b4, T79c0ff1T79c0ff0T79c0ff2Tb4b4b4, T79c0ff1T79c0ff0T79c0ff3Tb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3packetIdsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffnewTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3finalSettingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1T79c0ff0T79c0ff1Tb4b4b4, T79c0ff1T79c0ff0T79c0ff2Tb4b4b4, T79c0ff1T79c0ff0T79c0ff3Tb4b4b4)Tb4b4b4, Te6edf3registeredRequestIdsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3MANUAL_CHANNEL_WRITE_DELAYTb4b4b4, Te6edf3MANUAL_CHANNEL_WRITE_DELAYTb4b4b4)Tb4b4b4, Te6edf3delaysTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`applyManualChannelUpdatePlan invokes onInterrupted when writeChannel fails mid-plan`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3channelA Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff1Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3channelB Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff2Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3channelC Tff7b72= Te6edf3ChannelTb4b4b4(Te6edf3index Tff7b72= T79c0ff3Tb4b4b4, Te6edf3role Tff7b72= Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3writtenIndexes Tff7b72= Te6edf3mutableListOfTff7b72<Tffa657IntTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72var Te6edf3interruptedTb4b4b4: Te6edf3InterruptedManualChannelUpdate? Tff7b72= Tff7b72null

Tff7b72val Te6edf3error Tff7b72=
Te6edf3assertFailsWithTff7b72<Te6edf3IllegalStateExceptionTff7b72> Tb4b4b4{
Te6edf3applyManualChannelUpdatePlanTb4b4b4(
Te6edf3updatePlan Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3channelATb4b4b4, Te6edf3channelBTb4b4b4, Te6edf3channelCTb4b4b4)Tb4b4b4,
Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffoldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3finalSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffnewTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3writeChannel Tff7b72= Tb4b4b4{ Te6edf3channelTb4b4b4, Te6edf3onRequestId Tff7b72-Tff7b72>
Te6edf3writtenIndexesTb4b4b4.Te6edf3addTb4b4b4(Te6edf3channelTb4b4b4.Te6edf3indexTb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3channelTb4b4b4.Te6edf3index Tff7b72=Tff7b72= T79c0ff2Tb4b4b4) Tff7b72throw Te6edf3IllegalStateExceptionTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3id Tff7b72= Te6edf3channelTb4b4b4.Te6edf3index Tff7b72+ T79c0ff1T79c0ff0T79c0ff0
Te6edf3onRequestIdTb4b4b4(Te6edf3idTb4b4b4)
Te6edf3id
Tb4b4b4}Tb4b4b4,
Te6edf3registerRequestId Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4,
Te6edf3onInterrupted Tff7b72= Tb4b4b4{ Te6edf3interrupted Tff7b72= Tffa657it Tb4b4b4}Tb4b4b4,
Te6edf3delayFn Tff7b72= Tb4b4b4{Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffboomTa5d6ff"Tb4b4b4, Te6edf3errorTb4b4b4.Te6edf3messageTb4b4b4)
T8b949e// Channel A (index 1) completed before channel B (index 2) threw.
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4, Te6edf3writtenIndexesTb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3interruptedTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3interruptedTff7b72!!Tb4b4b4.Te6edf3appliedWriteCountTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3interruptedTff7b72!!Tb4b4b4.Te6edf3appliedSettingsTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3nameTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setResponseStateLoading for REBOOT calls useCase after config response`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
T8b949e// AdminRoute first sends a session key config request; the admin action fires
T8b949e// only after the actual ConfigResponse (not a routing ACK / Success).
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3ConfigTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3rebootTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3AdminRouteTb4b4b4.Te6edf3REBOOTTb4b4b4)

T8b949e// Emit a config response packet to trigger processPacketResponse -> sendAdminRequest
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3rebootTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setResponseStateLoading for FACTORY_RESET calls useCase after config response`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
T8b949e// AdminRoute first sends a session key config request; the admin action fires
T8b949e// only after the actual ConfigResponse (not a routing ACK / Success).
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3ConfigTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3factoryResetTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3AdminRouteTb4b4b4.Te6edf3FACTORY_RESETTb4b4b4)

T8b949e// Emit a config response packet to trigger processPacketResponse -> sendAdminRequest
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3factoryResetTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`NODEDB_RESET marks an expected local restart`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// Firmware reboots after a nodedb reset, so a local reset must open the restart window (like FACTORY_RESET)
T8b949e// or the ensuing transport drop surfaces as a surprise disconnect instead of "restarting".
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3ConfigTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3nodedbResetTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3AdminRouteTb4b4b4.Te6edf3NODEDB_RESETTb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3advanceUntilIdleTb4b4b4(Tb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3nodedbResetTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertTrueTb4b4b4(Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3restartExpectedTb4b4b4.Te6edf3valueTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`manual channel batch is not completed as success by a stale restart window`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// A prior local MAY_RESTART save opened the 90s restart window, but the node never actually rebooted (stayed
T8b949e// Connected, so onConnected never re-fired to close it early). A manual channel batch shares the save shape
T8b949e// (empty route + Loading); a transient drop inside the stale window must not flip the incomplete batch to
T8b949e// success and silently misreport a partial channel write.
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3connectionFlow Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3ConnectionStateTff7b72>Tb4b4b4(Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3connectionState Tb4b4b4} Te6edf3returns Te6edf3connectionFlow
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3expectRestartTb4b4b4(Tb4b4b4)

T8b949e// Enqueue a manual channel batch and leave its first write awaiting an ack (no packet emitted).
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRemoteChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff7T79c0ff7Tb4b4b4)
T79c0ff7T79c0ff7
Tb4b4b4}
Te6edf3viewModelTb4b4b4.Te6edf3updateChannelsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffNewTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3restartExpectedTb4b4b4.Te6edf3valueTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)

T8b949e// Transient transport drop inside the stale restart window.
Te6edf3connectionFlowTb4b4b4.Te6edf3value Tff7b72= Te6edf3ConnectionStateTb4b4b4.Te6edf3Disconnected
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertFalseTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3SuccessTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setPreserveFavorites updates state`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3test Tb4b4b4{
Te6edf3assertEqualsTb4b4b4(Tff7b72falseTb4b4b4, Te6edf3awaitItemTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3nodeDbResetPreserveFavoritesTb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3setPreserveFavoritesTb4b4b4(Tff7b72trueTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tff7b72trueTb4b4b4, Te6edf3awaitItemTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3nodeDbResetPreserveFavoritesTb4b4b4)
Te6edf3cancelAndIgnoreRemainingEventsTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setOwner calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffTest UserTa5d6ff"Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3userTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3userTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`saveUserConfig sends setHamMode for licensed local node`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ABCTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ATa5d6ff"Tb4b4b4, Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3userTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{
Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3HamParametersTb4b4b4(Te6edf3call_sign Tff7b72= Ta5d6ff"Ta5d6ffKK7ABCTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`saveUserConfig sends setOwner for unlicensed user`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffTest UserTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffTUTa5d6ff"Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3userTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3userTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`saveUserConfig never sends setHamMode to a remote node`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!100Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3remoteNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4, Te6edf3remoteNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ABCTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ATa5d6ff"Tb4b4b4, Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3userTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3userTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`saveUserConfig routes subsequent licensed saves to setOwner`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ABCTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ATa5d6ff"Tb4b4b4, Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff3

T8b949e// First save transitions OFF→ON and onboards via set_ham_mode.
Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3userTb4b4b4)
T8b949e// A later save while already licensed must use set_owner so other owner fields propagate.
Tff7b72val Te6edf3edited Tff7b72= Te6edf3userTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7BTa5d6ff"Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3editedTb4b4b4)

Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3editedTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`saveUserConfig routes licensed save to setOwner when myNodeInfo is absent`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ABCTa5d6ff"Tb4b4b4, Te6edf3short_name Tff7b72= Ta5d6ff"Ta5d6ffKK7ATa5d6ff"Tb4b4b4, Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3saveUserConfigTb4b4b4(Te6edf3userTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3userTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setHamModeTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setRingtone calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRingtoneTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3setRingtoneTb4b4b4(Ta5d6ff"Ta5d6ffringtone.mp3Ta5d6ff"Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffringtone.mp3Ta5d6ff"Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3ringtoneTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setRingtoneTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Ta5d6ff"Ta5d6ffringtone.mp3Ta5d6ff"Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setCannedMessages calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setCannedMessagesTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3setCannedMessagesTb4b4b4(Ta5d6ff"Ta5d6ffHello|WorldTa5d6ff"Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffHello|WorldTa5d6ff"Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3cannedMessageMessagesTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setCannedMessagesTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Ta5d6ff"Ta5d6ffHello|WorldTa5d6ff"Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`destNum from SavedStateHandle resolves destNode`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3destNodeTb4b4b4.Te6edf3valueTff7b72?.Te6edf3numTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setModuleConfig calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3config Tff7b72=
Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleConfigTb4b4b4(Te6edf3mqtt Tff7b72= Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleConfigTb4b4b4.Te6edf3MQTTConfigTb4b4b4(Te6edf3enabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setModuleConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setModuleConfigTb4b4b4(Te6edf3configTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setModuleConfigTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3configTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(Tff7b72trueTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3moduleConfigTb4b4b4.Te6edf3mqttTff7b72?.Te6edf3enabledTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setFixedPosition calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3pos Tff7b72= Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3coreTb4b4b4.Te6edf3modelTb4b4b4.Te6edf3PositionTb4b4b4(Te6edf3latitude Tff7b72= T79c0ff1.0Tb4b4b4, Te6edf3longitude Tff7b72= T79c0ff2.0Tb4b4b4, Te6edf3altitude Tff7b72= T79c0ff0Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setFixedPositionTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3setFixedPositionTb4b4b4(Te6edf3posTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setFixedPositionTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3posTb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`removeFixedPosition calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3removeFixedPositionTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3removeFixedPositionTb4b4b4(Tb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3removeFixedPositionTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`installProfile calls useCase`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3profile Tff7b72= Te6edf3DeviceProfileTb4b4b4(Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3installProfileUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Tffa657Unit

Te6edf3viewModelTb4b4b4.Te6edf3installProfileTb4b4b4(Te6edf3profileTb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3installProfileUseCaseTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3profileTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`processPacketResponse updates state on various results`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

T8b949e// ConfigResponse
Tff7b72val Te6edf3configResponse Tff7b72= Te6edf3ConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3hop_limit Tff7b72= T79c0ff5Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns
Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3configResponseTb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff5Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3radioConfigTb4b4b4.Te6edf3loraTff7b72?.Te6edf3hop_limitTb4b4b4)

T8b949e// ModuleConfigResponse
Tff7b72val Te6edf3moduleResponse Tff7b72=
Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleConfigTb4b4b4(
Te6edf3telemetry Tff7b72= Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleConfigTb4b4b4.Te6edf3TelemetryConfigTb4b4b4(Te6edf3device_update_interval Tff7b72= T79c0ff3T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns
Te6edf3RadioResponseResultTb4b4b4.Te6edf3ModuleConfigResponseTb4b4b4(Te6edf3moduleResponseTb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3T79c0ff0T79c0ff0Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3moduleConfigTb4b4b4.Te6edf3telemetryTff7b72?.Te6edf3device_update_intervalTb4b4b4)

T8b949e// Owner
Tff7b72val Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3long_name Tff7b72= Ta5d6ff"Ta5d6ffNew NameTa5d6ff"Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3OwnerTb4b4b4(Te6edf3userTb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffNew NameTa5d6ff"Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3userConfigTb4b4b4.Te6edf3long_nameTb4b4b4)

T8b949e// Ringtone
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3RingtoneTb4b4b4(Ta5d6ff"Ta5d6ffbell.mp3Ta5d6ff"Tb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ffbell.mp3Ta5d6ff"Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3ringtoneTb4b4b4)

T8b949e// Error
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns
Te6edf3RadioResponseResultTb4b4b4.Te6edf3ErrorTb4b4b4(Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3coreTb4b4b4.Te6edf3resourcesTb4b4b4.Te6edf3UiTextTb4b4b4.Te6edf3DynamicStringTb4b4b4(Ta5d6ff"Ta5d6ffFailTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3ErrorTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`Admin actions call correct useCases`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow

Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

T8b949e// SHUTDOWN
Te6edf3everySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3shutdownTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2
T8b949e// Set metadata to allow shutdown
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns
Te6edf3RadioResponseResultTb4b4b4.Te6edf3MetadataTb4b4b4(Te6edf3DeviceMetadataTb4b4b4(Te6edf3canShutdown Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3AdminRouteTb4b4b4.Te6edf3SHUTDOWNTb4b4b4)
T8b949e// AdminRoute fires sendAdminRequest after receiving ConfigResponse (session key),
T8b949e// not after a routing ACK (Success).
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3ConfigTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3shutdownTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}

T8b949e// NODEDB_RESET
Te6edf3everySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3nodedbResetTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2
Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3AdminRouteTb4b4b4.Te6edf3NODEDB_RESETTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3ConfigResponseTb4b4b4(Te6edf3ConfigTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3adminActionsUseCaseTb4b4b4.Te6edf3nodedbResetTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`setResponseStateLoading for various routes calls correct useCases`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

T8b949e// USER
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}
Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertTrueTb4b4b4(Tb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72as Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)Tb4b4b4.Te6edf3showOverlayTb4b4b4)

T8b949e// CHANNELS
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getChannelTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2
Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3CHANNELSTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getChannelTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, T79c0ff0Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3verifySuspend Tb4b4b4{
Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getConfigTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3AdminMessageTb4b4b4.Te6edf3ConfigTypeTb4b4b4.Te6edf3LORA_CONFIGTb4b4b4.Te6edf3valueTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// LORA
Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3LORATb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getConfigTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3ConfigRouteTb4b4b4.Te6edf3LORATb4b4b4.Te6edf3typeTb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`loadConfigRoute hides progress overlay for local settings refresh`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3loadConfigRouteTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3loading Tff7b72= Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72as Te6edf3ResponseStateTb4b4b4.Te6edf3Loading
Te6edf3assertFalseTb4b4b4(Te6edf3loadingTb4b4b4.Te6edf3showOverlayTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`loadConfigRoute shows progress overlay for remote settings refresh`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!100Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3remoteNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4, Te6edf3remoteNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3loadConfigRouteTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3loading Tff7b72= Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72as Te6edf3ResponseStateTb4b4b4.Te6edf3Loading
Te6edf3assertTrueTb4b4b4(Te6edf3loadingTb4b4b4.Te6edf3showOverlayTb4b4b4)
Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`registerRequestId timeout clears request and sets error`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getOwnerTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff4T79c0ff2Tb4b4b4)
T79c0ff4T79c0ff2
Tb4b4b4}

Te6edf3viewModelTb4b4b4.Te6edf3setResponseStateLoadingTb4b4b4(Te6edf3ConfigRouteTb4b4b4.Te6edf3USERTb4b4b4)

T8b949e// state should be loading
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)

T8b949e// advance time past 30 seconds
Te6edf3advanceTimeByTb4b4b4(T79c0ff3T79c0ff1Te6edf3_000Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

T8b949e// after timeout, the request ID should be removed, and if empty, sendError is called.
T8b949e// It's hard to assert sendError directly without a mock on a channel, but we can verify it doesn't stay loading
T8b949e// actually sendError updates the state? No, sendError sends an event.
T8b949e// But the requestIds gets cleared.
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`ensureLoadingForRemote sets loading state for remote nodes`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!100Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3remoteNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4, Te6edf3remoteNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3remoteVm Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)

T8b949e// Remote VM starts with Empty responseState
Te6edf3assertEqualsTb4b4b4(Te6edf3ResponseStateTb4b4b4.Te6edf3EmptyTb4b4b4, Te6edf3remoteVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseStateTb4b4b4)
Te6edf3assertFalseTb4b4b4(Te6edf3remoteVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3isLocalTb4b4b4)

T8b949e// ensureLoadingForRemote should transition to Loading
Te6edf3remoteVmTb4b4b4.Te6edf3ensureLoadingForRemoteTb4b4b4(Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3remoteVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`ensureLoadingForRemote is no-op for local session before node identity resolves`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localVm Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= Tff7b72nullTb4b4b4)

Te6edf3localVmTb4b4b4.Te6edf3ensureLoadingForRemoteTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ResponseStateTb4b4b4.Te6edf3EmptyTb4b4b4, Te6edf3localVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseStateTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`ensureLoadingForRemote is no-op when already loading`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!100Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3remoteNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4, Te6edf3remoteNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)

Tff7b72val Te6edf3remoteVm Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)

T8b949e// Set loading first
Te6edf3remoteVmTb4b4b4.Te6edf3ensureLoadingForRemoteTb4b4b4(Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3remoteVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)

T8b949e// Calling again should still be Loading (no-op, not a new instance)
Te6edf3remoteVmTb4b4b4.Te6edf3ensureLoadingForRemoteTb4b4b4(Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3remoteVmTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`loraRegionPresetMapFlow populates state`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3mapFlow Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3LoRaRegionPresetMap?Tff7b72>Tb4b4b4(Tff7b72nullTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3loraRegionPresetMapFlow Tb4b4b4} Te6edf3returns Te6edf3mapFlow
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Tff7b72nullTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3loraRegionPresetMapTb4b4b4)

Tff7b72val Te6edf3map Tff7b72= Te6edf3LoRaRegionPresetMapTb4b4b4(Te6edf3groups Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3LoRaPresetGroupTb4b4b4(Te6edf3licensed_only Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3mapFlowTb4b4b4.Te6edf3value Tff7b72= Te6edf3map
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertEqualsTb4b4b4(Te6edf3mapTb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3loraRegionPresetMapTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`localIsLicensed tracks the destination node's is_licensed flag`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4, Te6edf3is_licensed Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3localIsLicensedTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`LoRa setConfig is not applied optimistically and issues no re-read`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// A firmware region swap (e.g. EU sibling) is applied live; the form must reflect the device's actual
T8b949e// value, which is re-read on next LoRa-screen entry — NOT applied optimistically here, and the save ACK
T8b949e// must not trigger an in-place re-read (that would suppress the normal save-success UX).
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3packetFlow Tff7b72= Te6edf3MutableSharedFlowTff7b72<Te6edf3MeshPacketTff7b72>Tb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3meshPacketFlow Tb4b4b4} Te6edf3returns Te6edf3packetFlow
Te6edf3every Tb4b4b4{ Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3localConfigFlow Tb4b4b4} Te6edf3returns
Te6edf3MutableStateFlowTb4b4b4(Te6edf3LocalConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3region Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3EU_868Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3region Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

T8b949e// The optimistic state still reflects the device's value, not the requested region.
Te6edf3assertEqualsTb4b4b4(Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3EU_868Tb4b4b4, Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3radioConfigTb4b4b4.Te6edf3loraTff7b72?.Te6edf3regionTb4b4b4)

Te6edf3every Tb4b4b4{ Te6edf3processRadioResponseUseCaseTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3RadioResponseResultTb4b4b4.Te6edf3Success
Te6edf3packetFlowTb4b4b4.Te6edf3emitTb4b4b4(Te6edf3MeshPacketTb4b4b4(Te6edf3decoded Tff7b72= Te6edf3DataTb4b4b4(Te6edf3request_id Tff7b72= T79c0ff4T79c0ff2Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3getConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`backupSecurityKeys refuses to persist empty keys`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

T8b949e// Empty SecurityConfig is the fallback before the device's config response arrives — backing it up and later
T8b949e// restoring it would wipe the device's real keys with blanks.
Te6edf3viewModelTb4b4b4.Te6edf3backupSecurityKeysTb4b4b4(Te6edf3ConfigTb4b4b4.Te6edf3SecurityConfigTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3verifyTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3securityKeyBackupStoreTb4b4b4.Te6edf3saveTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`backupSecurityKeys persists real keys`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3config Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3SecurityConfigTb4b4b4(Te6edf3public_key Tff7b72= Ta5d6ff"Ta5d6ffpubTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3private_key Tff7b72= Ta5d6ff"Ta5d6ffprivTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3backupSecurityKeysTb4b4b4(Te6edf3configTb4b4b4)

T8b949e// Pin the exact base64 so a public/private swap or encoding change is caught.
Te6edf3verify Tb4b4b4{ Te6edf3securityKeyBackupStoreTb4b4b4.Te6edf3saveTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Ta5d6ff"Ta5d6ffcHViTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffcHJpdg==Ta5d6ff"Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`restoreSecurityKeys is a no-op when no backup exists`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3securityKeyBackupStoreTb4b4b4.Te6edf3getTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4) Tb4b4b4} Te6edf3returns Tff7b72null

Te6edf3viewModelTb4b4b4.Te6edf3restoreSecurityKeysTb4b4b4(Tb4b4b4)

Te6edf3verifySuspendTb4b4b4(Te6edf3exactlyTb4b4b4(T79c0ff0Tb4b4b4)Tb4b4b4) Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`restoreSecurityKeys pushes decoded config to the device on success`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)

Tff7b72val Te6edf3stored Tff7b72= Te6edf3StoredSecurityKeysTb4b4b4(Te6edf3publicKeyBase64 Tff7b72= Ta5d6ff"Ta5d6ffcHViTa5d6ff"Tb4b4b4, Te6edf3privateKeyBase64 Tff7b72= Ta5d6ff"Ta5d6ffcHJpdg==Ta5d6ff"Tb4b4b4, Te6edf3timestamp Tff7b72= T79c0ff1LTb4b4b4)
Tff7b72val Te6edf3decoded Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3SecurityConfigTb4b4b4(Te6edf3public_key Tff7b72= Ta5d6ff"Ta5d6ffpubTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3private_key Tff7b72= Ta5d6ff"Ta5d6ffprivTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3securityKeyBackupStoreTb4b4b4.Te6edf3getTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3stored
Te6edf3every Tb4b4b4{ Te6edf3importSecurityConfigUseCaseTb4b4b4(Te6edf3storedTb4b4b4) Tb4b4b4} Te6edf3returns Te6edf3ResultTb4b4b4.Te6edf3successTb4b4b4(Te6edf3decodedTb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3viewModelTb4b4b4.Te6edf3restoreSecurityKeysTb4b4b4(Tb4b4b4)

Te6edf3verifySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3ConfigTb4b4b4(Te6edf3security Tff7b72= Te6edf3decodedTb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8fffourChannelFixtureTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffmyNodeInfoTb4b4b4(Te6edf3myNodeNumTb4b4b4: Tffa657IntTb4b4b4) Tff7b72= Te6edf3MyNodeInfoTb4b4b4(
Te6edf3myNodeNum Tff7b72= Te6edf3myNodeNumTb4b4b4,
Te6edf3hasGPS Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3model Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3firmwareVersion Tff7b72= Tff7b72nullTb4b4b4,
Te6edf3couldUpdate Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3shouldUpdate Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3currentPacketId Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3messageTimeoutMsec Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3minAppVersion Tff7b72= T79c0ff0Tb4b4b4,
Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4,
Te6edf3hasWifi Tff7b72= Tff7b72falseTb4b4b4,
Te6edf3channelUtilization Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3airUtilTx Tff7b72= T79c0ff0fTb4b4b4,
Te6edf3deviceId Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4)

Tf0883e@Test
Tff7b72fun Td2a8ff`local reboot-applying config save opens the restart window`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3onConnectedTb4b4b4(Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3network Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3NetworkConfigTb4b4b4(Te6edf3wifi_enabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3restartExpectedTb4b4b4.Te6edf3valueTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`reboot-applying save resolves to restarting-success when the node drops`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
T8b949e// The reboot the save triggers eats the routing ACK; the transport-drop during the restart window is the
T8b949e// real confirmation, so the save dialog must show success ("restarting") rather than a 30s timeout error.
Tff7b72val Te6edf3node Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!123Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3nodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff2T79c0ff3Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3connFlow Tff7b72= Te6edf3MutableStateFlowTff7b72<Te6edf3ConnectionStateTff7b72>Tb4b4b4(Te6edf3ConnectionStateTb4b4b4.Te6edf3ConnectedTb4b4b4)
Te6edf3every Tb4b4b4{ Te6edf3serviceRepositoryTb4b4b4.Te6edf3connectionState Tb4b4b4} Te6edf3returns Te6edf3connFlow
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3calls
Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3argsTb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4(T79c0ff7T79c0ff7Tb4b4b4)
T79c0ff7T79c0ff7
Tb4b4b4}

Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3onConnectedTb4b4b4(Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3network Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3NetworkConfigTb4b4b4(Te6edf3wifi_enabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3LoadingTb4b4b4)

T8b949e// The node reboots and the transport drops.
Te6edf3connFlowTb4b4b4.Te6edf3value Tff7b72= Te6edf3ConnectionStateTb4b4b4.Te6edf3Disconnected
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertTrueTb4b4b4(Te6edf3viewModelTb4b4b4.Te6edf3radioConfigStateTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3responseState Tff7b72is Te6edf3ResponseStateTb4b4b4.Te6edf3SuccessTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`remote config save does not open the restart window`Tb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3localNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!100Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3remoteNode Tff7b72= Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4, Te6edf3user Tff7b72= Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Ta5d6ff"Ta5d6ff!456Ta5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setNodesTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3localNodeTb4b4b4, Te6edf3remoteNodeTb4b4b4)Tb4b4b4)
Te6edf3nodeRepositoryTb4b4b4.Te6edf3setMyNodeInfoTb4b4b4(Te6edf3myNodeInfoTb4b4b4(Te6edf3myNodeNum Tff7b72= T79c0ff1T79c0ff0T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3viewModel Tff7b72= Te6edf3createViewModelTb4b4b4(Te6edf3destNum Tff7b72= T79c0ff4T79c0ff5T79c0ff6Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)
Te6edf3everySuspend Tb4b4b4{ Te6edf3radioConfigUseCaseTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3anyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4} Te6edf3returns T79c0ff4T79c0ff2

Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3onConnectedTb4b4b4(Tb4b4b4)
Te6edf3viewModelTb4b4b4.Te6edf3setConfigTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3network Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3NetworkConfigTb4b4b4(Te6edf3wifi_enabled Tff7b72= Tff7b72trueTb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3runCurrentTb4b4b4(Tb4b4b4)

Te6edf3assertFalseTb4b4b4(Te6edf3nodeRestartTrackerTb4b4b4.Te6edf3restartExpectedTb4b4b4.Te6edf3valueTb4b4b4)
Tb4b4b4}
Tb4b4b4}

T8b949e/** Extracts the trailing `onRequestId` callback from a mocked request method's args. */
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffUNCHECKED_CASTTa5d6ff"Tb4b4b4)
Tff7b72private Tff7b72fun Td2a8ffListTff7b72<Tffa657Any?Tff7b72>Tb4b4b4.Te6edf3onRequestIdArgTb4b4b4(Tb4b4b4)Tb4b4b4: Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657Unit Tff7b72= Te6edf3lastTb4b4b4(Tb4b4b4) Tff7b72as Tb4b4b4(Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657Unit

Served by rngit 1.5.0 - Generated in 0.38s